package com.gitee.wsl.flow.combine

import com.gitee.wsl.base.tuple
import com.gitee.wsl.flow.F
import com.gitee.wsl.flow.state.DerivedStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine


fun <T1, T2, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    transform: (a: T1, b: T2) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value)
        },
        flow = combine(a, b) { a, b ->
            transform(a, b)
        }
    )
}

fun <T1, T2> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
) = combineStateFlows(a,b){a, b -> a to b}

fun <T1, T2, T3, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    transform: (a: T1, b: T2, c: T3) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value, c.value)
        },
        flow = combine(a, b, c) { a, b, c ->
            transform(a, b, c)
        }
    )
}

inline fun <reified T1, reified T2, reified T3> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>
) = combineStateFlows(a,b, c){a, b, c -> tuple(a,b,c)}

fun <T1, T2, T3, T4, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    transform: (a: T1, b: T2, c: T3, d: T4) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value, c.value, d.value)
        },
        flow = combine(a, b, c, d) { a, b, c, d ->
            transform(a, b, c, d)
        }
    )
}

inline fun <reified T1, reified T2, reified T3, reified T4, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>
) = combineStateFlows(a,b, c,d){a, b, c ,d-> tuple(a,b,c,d)}

fun <T1, T2, T3, T4, T5, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>,
    transform: (a: T1, b: T2, c: T3, d: T4, e: T5) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value, c.value, d.value, e.value)
        },
        flow = combine(a, b, c, d, e) { a, b, c, d, e ->
            transform(a, b, c, d, e)
        }
    )
}

inline fun <reified T1, reified T2, reified T3, reified T4, reified T5> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>
)= combineStateFlows(a,b, c,d,e){a, b, c , d, e-> tuple(a,b,c,d,e)}

fun <T1, T2, T3, T4, T5, T6, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>,
    f: StateFlow<T6>,
    transform: (a: T1, b: T2, c: T3, d: T4, e: T5, f: T6) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value, c.value, d.value, e.value, f.value)
        },
        flow = combine(a, b, c, d, e, f) { array ->
            @Suppress("UNCHECKED_CAST")
            transform(array[0] as T1, array[1] as T2, array[2] as T3, array[3] as T4, array[4] as T5, array[5] as T6)
        }
    )
}

inline fun <reified T1, reified T2, reified T3, reified T4, reified T5, reified T6> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>,
    f: StateFlow<T6>
)= combineStateFlows(a,b, c,d,e,f){a, b, c , d, e, f-> tuple(a,b,c,d,e,f)}

fun <T1, T2, T3, T4, T5, T6, T7, R> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>,
    f: StateFlow<T6>,
    g: StateFlow<T7>,
    transform: (a: T1, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(a.value, b.value, c.value, d.value, e.value, f.value, g.value)
        },
        flow = combine(a, b, c, d, e, f) { array ->
            @Suppress("UNCHECKED_CAST")
            transform(
                array[0] as T1,
                array[1] as T2,
                array[2] as T3,
                array[3] as T4,
                array[4] as T5,
                array[5] as T6,
                array[6] as T7,
            )
        }
    )
}

inline fun <reified T1,reified  T2,reified  T3,reified  T4, reified T5, reified T6, reified T7> F.combineStateFlows(
    a: StateFlow<T1>,
    b: StateFlow<T2>,
    c: StateFlow<T3>,
    d: StateFlow<T4>,
    e: StateFlow<T5>,
    f: StateFlow<T6>,
    g: StateFlow<T7>
) = combineStateFlows(a,b, c,d,e,f,g){a, b, c , d, e, f,g-> tuple(a,b,c,d,e,f,g)}

inline fun <reified T, R> F.combineStateFlows(
    flows: Iterable<StateFlow<T>>,
    noinline transform: (list: Array<T>) -> R
): StateFlow<R> {
    return DerivedStateFlow(
        getValue = {
            transform(
                flows
                    .map { it.value }
                    .toTypedArray()
            )
        },
        flow = combine(flows) {
            transform(it)
        }
    )
}

inline fun <reified T, R> F.combineStateFlows(
    vararg flows: StateFlow<T>,
    noinline transform: (list: Array<T>) -> R
): StateFlow<R> {
    return combineStateFlows(listOf(*flows), transform)
}